#include <stdlib.h>
#include <stdio.h>
#include "Event.h"

//random[0]是两个到达事件的间隔
int random[3];
int lastArrTime=0;
int lastLeaveTime=0;
int waitTime=0;
int averageTime=0;
double total=0,lastTotal=0;
LQueue queue1;
LQueue queue2;
LinkedList list;
int closeTime=0;
int listCount=0;
int scan[6];
int no=1;
Status SetRandom(int random[] ,int scan[]){
//    for (int i = 0; i <= 5; ++i) {
//        printf("%d\n",scan[i]);
//    }
    random[0]=rand()%(scan[0]-scan[1])+scan[1];//arrtime
    random[1]=rand()%(scan[2]-scan[3])+scan[3];//durtime
    random[2]=rand()%(scan[4]-scan[5])+scan[5];//amount

    /*
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(1, 100);

    // 生成随机数
    int random_number = distribution(generator);
     */
    return OK;
}

Status SetTime(CustNode* p ,long arrtime,long durtime,double amount){
    p->amount=amount;
    p->arrtime=arrtime;
    p->durtime=durtime;
    return OK;
}


Status initEventLinkedList(LinkedList &L) {
    //初始化一个只含头结点的空单链表事件表L
    {
        if (NULL == (L = (Event *) malloc(sizeof(Event))))//分配头结点的空间
            return OVERFLOW;
        //rear=L;
        L->type=-1;//头结点
        L->time=0;
        L->next = NULL;//头结点的next城为空
        return OK;
    }
}


// 添加事件到事件表
Event* addEvent(LinkedList &L,int time, int type,CustNode * node) {
    Event* newEvent = (struct Event*)malloc(sizeof(struct Event));
    newEvent->time = time;
    newEvent->type = type;
    if (type==0){
        newEvent->no=node->no;
        lastLeaveTime=time;
        averageTime+=time-node->arrtime;
        node->leavetime=time;
    } else{
        newEvent->no=no++;
        node->no=newEvent->no;
        node->arrtime=time;

    }
    newEvent->custNode=node;
    newEvent->next = NULL;
    //printf("%ld\n",newEvent->custNode->arrtime);
    // 插入到有序事件表中
    //按照时间顺序插入，即每个事件都是插入到单链表的尾部
    Event* current = L;
    //if (!current)L->next=newEvent;

    //Event* firstEvent=L->next;
    //rear->next=newEvent;
    //rear=newEvent;

    //else{
    while (current->next!= NULL && current->next->time <= time) {
        current = current->next;
    }
    //printf("%d1\n",newEvent->time);

    newEvent->next = current->next;
    current->next = newEvent;
    return newEvent;
}

// 处理事件表中的事件
Status processEvents(LinkedList &L,LQueue &queue,Event *currentEvent) {//执行processEvent函数前先重新生成随机数
    if (!L||!currentEvent)return ERROR;
    //Event* currentEvent = L->next;

    if (currentEvent->type==1){
        //当处理当前客户的到达事件时，就生成下一个客户结点，设置随机数
        CustNode* nextNode=myMalloc();
        SetRandom(random,scan);
        int time=random[0]+lastArrTime;
        //printf("%d\n",closeTime);
        //printf("%d\n",time);
        if (time>closeTime){
            return OVERFLOW;
        }
        SetTime(nextNode,time,random[1],random[2]);

        //将下一到达事件插入事件表
        Event *e=addEvent(L,time,1,nextNode);
        //printf("%ld\n",e->custNode->arrtime);

        lastArrTime+=random[0];

        //入队
        EnQueue_LQ(queue1,nextNode);
        //

    }else if (currentEvent->type==0){
        //离开事件

        //即存钱的从第一个队列出队
        //取钱的分两种情况
        //一种是满足需求，从第一个队列出队，并入栈
        //另一种是不满足需求，从第一个队列出队，并入第二个队列



        //从队列出队
        CustNode * DepartureNode=DeQueue_LQ(queue);
        //printf("depart%x\n",DepartureNode);

        //入栈
        myFree(DepartureNode);
    }


    // 处理当前事件
    // ...

    // 释放当前事件的内存
    //free(currentEvent);
    return TRUE;

}

Status checkNode(LQueue &Q){

    CustNode *custNode=Q.front;
    //printf("other%x\n",custNode);
    // 以下代码是正确的
    if (custNode->amount<0&& (-custNode->amount)>total){
        //取钱客户，且需求不满足,直接从queue1出队，并在queue2入队
        CustNode *node=DeQueue_LQ(Q);
        printf("%d\t%ld\t%ld\t%.2f\n",node->no,node->arrtime,node->durtime,node->amount);
        EnQueue_LQ(queue2,node);

    }
    else{

            //直接添加离开事件
            //取钱但满足需求
            // 还钱或存钱
        // 此时amount>=0或可以满足需求
        total+=custNode->amount;
        //printf("%f\n",custNode->amount);

        if (custNode->amount>=0){

            lastTotal=total-custNode->amount;
            //printf("lasttotal%f\n",lastTotal);

            //每接待完一个第二种业务的客户，就检查第二个队列
            checkQueue();
        }
        //printf("%f\n",total);

        //第一类客户满足需求和第二类客户

        if (lastLeaveTime>custNode->arrtime){
            custNode->leavetime=lastLeaveTime+custNode->durtime;
        } else{
            custNode->leavetime=custNode->arrtime+custNode->durtime;
        }

        //printf("%ld\n",custNode->leavetime);
        Event *event=addEvent(list,custNode->leavetime,0,custNode);//离开时间要修改，还要加上等待时间
        processEvents(list,queue1,event);
    }
    return OK;
}
//接待完第二种客户后检查第二个队列
Status checkQueue(){
//第二个队列肯定是取钱的，amount<0
    CustNode *p=queue2.front,*q=queue2.rear;
    if (p==NULL&&q==NULL){
        return FALSE;
    }
    Event *event;
    do{
        if (total<lastTotal){
            //银行资金总额少于或等于刚才第一个队列中最后一个客户(第二种业务)被接待之前的数额
            break;
        }
        if ((-p->amount)<total){
            //满足需求
            //从第二个队列出队

            //添加离开事件
            total+=p->amount;
            p->leavetime=lastLeaveTime+p->durtime;
            event=addEvent(list,p->leavetime,0,p);

            processEvents(list,queue2,event);
            //return TRUE;
        } else{
            //若不满足需求，则排到队列最后面
            //先从第二个队列出队,然后再入队列2的尾部
            EnQueue_LQ(queue2,DeQueue_LQ(queue2));
        }

        p=p->next;
    }while (p!=q&&p!=NULL&&queue2.front!=NULL);

    return TRUE;
}

void simulate(int scanBound[],double total0,int closetime) {

    initEventLinkedList(list);
    InitQueue_LQ(queue1);
    InitQueue_LQ(queue2);
    InitStack_LS();

    total=total0;
    closeTime=closetime;
    for (int i = 0; i <= 5; ++i) {
        scan[i]=scanBound[i];
        //printf("%d\n",scan[i]);
    }

    //第一个到达的客户
    CustNode* firstNode=myMalloc();
    SetRandom(random,scan);

    SetTime(firstNode,random[0],random[1],random[2]);
    addEvent(list,random[0],1,firstNode);
    lastArrTime+=random[0];
    EnQueue_LQ(queue1,firstNode);
    int currentTime=lastArrTime;
    Event *event=list->next;
    //checkNode(queue1,firstNode);



    while (currentTime < closeTime) {
        //生成到达时间事件

        int nextEventTime = event->time;

        // 处理事件
        if (nextEventTime == currentTime) {

            if (processEvents(list,queue1,event)==OVERFLOW){
                break;
            }
            //printf("%d\n",1);
            event=event->next;
        }

        // 处理离开事件
        //processDeparture();

        // 更新当前时间
        currentTime = nextEventTime;
    }

    int expectedTime=0;
    while(queue1.front!=NULL&&expectedTime<=closetime){
        //检查queue1队列
        checkNode(queue1);
        if (queue1.front!=NULL){
            if (lastLeaveTime>queue1.front->arrtime){
                expectedTime=lastLeaveTime+queue1.front->durtime;
            } else{
                expectedTime=queue1.front->arrtime+queue1.front->durtime;
            }
        }

        //队列1 中不能在营业结束前完成业务的顾客直接用营业时间-到达时间arrtime



    }
    CustNode *node1=DeQueue_LQ(queue1);
    while(node1){
        addEvent(list,closetime,0,node1);
        myFree(node1);
        node1=DeQueue_LQ(queue1);
    }
    CustNode *node2= DeQueue_LQ(queue2);
    while (node2){
        addEvent(list,closetime,0,node2);
        myFree(node2);
        node2=DeQueue_LQ(queue2);
    }

    //printList();

}
void average(){
    printf("客户平均逗留时间为: %f 分钟\n",averageTime*1.0/(no-1));
}
void totalTime(){
    printf("客户总逗留时间为: %d 分钟\n",averageTime);
}
void totalCustomer(){
    printf("总用户数: %d\n",no-1);
}
void Destroy(){
    DestroyQueue_LQ(queue1);
    DestroyQueue_LQ(queue2);
    DestroyList(list);
    DestroyStack_LS();
}

int getListCount(LinkedList L){
    if (L->next == NULL)  return 0;
    Event *p = L->next;

    while (p != NULL) {
        listCount++;
        p = p->next;
    }
    return listCount;
}
void printCustomer(){
    Event *p=list->next;
    if (p==NULL){
        printf("没有到达的客户\n");
    }
    printf("客户编号   到达时间   离开时间    交易金额   交易时间长度\n");
    while(p){
        if (p->type==1){
            if (p->custNode->leavetime==0){
                p->custNode->leavetime=600;
                //卡在队列2里直到银行营业结束都不能满足需求
            }
            printf("   %d\t  %ld\t   %ld\t    %.2f\t%ld\n",p->no,p->custNode->arrtime,p->custNode->leavetime,p->custNode->amount,p->custNode->durtime);

            //其他客户离开时间为closetime的不是因为不能满足需求，而是因为前面还有人在等待
            //printf("\n");
        }

        p=p->next;
    }
}
void printList(){
    if (list == NULL)  return ;
    Event *p = list->next;
    printf("\n遍历结果 :\n");
    printf(" 客户序号：      事件触发时间：             事件类型：   ");
    printf("\n------------------------------------------------------------");
    while (p != NULL) {
        printf("\n   %d		 %d", p->no, p->time);
        if (p->type == 1) {
            printf("			到达");
            printf("\n--------------------------------------------------------------");
        }
        else {
            printf("			离开");
            printf("\n-------------------------------------------------------------");
        }
        p = p->next;
    }
    printf("\n");
}

void DestroyList(LinkedList &lists){
    if (lists != NULL){
        Event *p = lists->next;
        Event * k = p;
        while (p != NULL)
        {
            free(p);
            p = k->next;
            k=k->next;

        }
        free(lists);
    }
}
